package controller

import (
	"net/http"
	"reflect"

	"gitee.com/xxhsjp/x-core/app"
	"gitee.com/xxhsjp/x-core/utils"
	"gitee.com/xxhsjp/x-web/response"

	"gitee.com/xxhsjp/x-core/enums"
	"gitee.com/xxhsjp/x-core/exception"
	ex "gitee.com/xxhsjp/x-web/exception"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type Base struct {
}

func (*Base) Success(data any) *response.StdResp {
	return &response.StdResp{Code: enums.Success.Code, Data: data}
}

func (*Base) Failure(code string, msg string) *response.StdResp {
	return &response.StdResp{Code: code, Msg: msg}
}

func (*Base) FailureWithError(err error) *response.StdResp {
	if bizerror, ok := errors.Cause(err).(exception.BizException); ok {
		logrus.Infof("code: %v err: %+v", bizerror.Code(), bizerror.Error())
		return &response.StdResp{Code: bizerror.Code(), Msg: bizerror.Error()}
	} else {
		logrus.Errorf("code: %v err: %+v", bizerror.Code(), bizerror.Error())
		return &response.StdResp{Code: app.App.Code + enums.SysError.Code, Msg: enums.SysError.Text}
	}
}

func (*Base) JSON(ctx *gin.Context, resp *response.StdResp) {
	ctx.JSON(http.StatusOK, resp)
}

func (*Base) Bind(bind ginBindFunc, obj any) error {
	err := bind(obj)
	var ve validator.ValidationErrors
	if errors.As(err, &ve) {
		for _, v := range ve {
			sf, _ := reflect.TypeOf(obj).Elem().FieldByName(v.Field())
			msg := utils.TrueReturnX(sf.Tag.Get("msg") == "", enums.ParamInvalid.Text, sf.Tag.Get("msg"))
			return ex.NewBindException(msg)
		}
	}

	return err
}

type ginBindFunc func(obj any) error
